﻿using System;
using System.IO;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.ComponentModel;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using ESCommon;
using ESCommon.Rtf;

namespace NCS_CS
{
    public partial class FormRtfC : Form
    {
        public const int WM_USER = 0x400;
        public const int EM_FORMATRANGE = (WM_USER + 57);
        PageInfo[] AllPages;//= null;
        int lngPageCount;

        [System.Runtime.InteropServices.DllImport("user32.dll")]
        static extern int SendMessage(IntPtr hWnd, int Msg, uint wParam, uint lParam);
        public FormRtfC()
        {
            InitializeComponent();
        }
        private void button1_Click_1(object sender, EventArgs e)
        {
            button1.Enabled = false;
            button1.Enabled = true;
        }

        private void FormRtfC_Load(object sender, EventArgs e)
        {
            ReportRtfc report = new ReportRtfc();
            RtfDocument rtf = report.GetRtf();
            RtfWriter rtfWriter = new RtfWriter();
            this.richTextBox1.Rtf = rtfWriter.Write(rtf);
        }

        private void button2_Click(object sender, EventArgs e)
        {
            DoVirtualPrint(ref this.richTextBox1);
        }
        private void PrintPage(ref RichTextBox RTF, int PageNumber, ref PictureBox objTarget)
        {
            //    Optional ByRef objTarget As Object = Nothing)
            objTarget.CreateGraphics().Clear(Color.White);
            int MarginLeft = 100;
            int MarginTop = 100;
            int MarginBottom = 100;
            int MarginRight = 100;//todo use twips
            int lngOffsetLeft;// As Long       '左边缘偏移量
            int lngOffsetTop;// As Long            '上边缘偏移量
            int lngLeft;// As Long
            int lngTop;// As Long
            int lngRight;// As Long
            int lngBottom;// As Long
            //    Dim lngPageCount As Long        '总页数

            FORMATRANGE fr;//           '格式化的文本范围
            RECT rcDrawTo;// As rect            '目标文字区域
            RECT rcPage;// As rect              '目标页面区域
            int lngNextPos;// As Long          '下一个字符位置
            int R;// As Long                   '返回值

            //    If objTarget Is Nothing Then Set objTarget = Printer
            //    '开始一个打印作业，用于获取有效的目标设备上下文句柄 hDC
            //    objTarget.ScaleMode = vbTwips   '设置打印机单位为缇。

            //    '获取打印机可打印区域的边缘偏移量，单位：Pixel
            int xbias = SomeUtils.GetDeviceCaps(objTarget.CreateGraphics().GetHdc(), DeviceCap.PHYSICALOFFSETX);
            lngOffsetLeft = SomeUtils.ConvertPixelsToTwips(xbias, MeasureDirection.Horizontal);
            int ybias = SomeUtils.GetDeviceCaps(objTarget.CreateGraphics().GetHdc(), DeviceCap.PHYSICALOFFSETY);
            lngOffsetTop = SomeUtils.ConvertPixelsToTwips(ybias, MeasureDirection.Vertical);
            //    lngOffsetTop = objTarget.ScaleY(GetDeviceCaps(objTarget.hdc, PHYSICALOFFSETY), vbPixels, vbTwips)
            int wtwips = SomeUtils.ConvertPixelsToTwips(objTarget.Width, MeasureDirection.Horizontal);
            int htwips = SomeUtils.ConvertPixelsToTwips(objTarget.Height, MeasureDirection.Horizontal);
            //    '设置可打印页面区域
            rcPage.Left = 0;
            rcPage.Top = 0;
            rcPage.Right = wtwips;
            rcPage.Bottom = htwips;

            //    '设置可打印文字区域
            lngLeft = MarginLeft - lngOffsetLeft;
            lngTop = MarginTop - lngOffsetTop;
            lngRight = (wtwips - MarginRight);
            lngBottom = (htwips - MarginBottom);

            rcDrawTo.Left = lngLeft;
            rcDrawTo.Top = lngTop;
            rcDrawTo.Right = lngRight;
            rcDrawTo.Bottom = lngBottom;

            //    '设置打印指令（FormatRange消息需要的打印信息）
            IntPtr hdc = objTarget.CreateGraphics().GetHdc();
            fr.hdc = hdc;//              ' 度量和渲染使用相同的DC
            fr.hdcTarget = hdc;//         ' 目标控件的DC
            fr.rc = rcDrawTo; //                 ' 文字矩形区域 IN/OUT
            fr.rcPage = rcPage;//                 ' 整个页面矩形区域 IN
            fr.chrg.cpMin = AllPages[PageNumber-1].Start;//      ' 打印区域的文字开始位置
            fr.chrg.cpMax = AllPages[PageNumber-1].End;//   ' 文字结束位置（-1表示直到末尾）

            //    '发送 EM_FORMATRANGE 消息进行打印
            IntPtr p1 = Marshal.AllocHGlobal(Marshal.SizeOf(fr));
            Marshal.StructureToPtr(fr, p1, true);
            lngNextPos = SendMessage(RTF.Handle, EM_FORMATRANGE, (uint)0, (uint)p1);
            if (lngNextPos < AllPages[PageNumber-1].End) { fr.rc.Bottom = fr.rc.Bottom + 1000; }//    '保证一次打印完整页
            IntPtr p2 = Marshal.AllocHGlobal(Marshal.SizeOf(fr));
            Marshal.StructureToPtr(fr, p2, true);
            lngNextPos = SendMessage(RTF.Handle, EM_FORMATRANGE, (uint)1, (uint)p2);

            //允许RTF释放内存
            R = SendMessage(RTF.Handle, EM_FORMATRANGE, 0, 0);
        }

        //########################################################
        //## 功能：  执行虚拟打印，更新RTF的分页信息
        //########################################################
        private void DoVirtualPrint(ref RichTextBox rtf)
        {
            int lngLeft;
            int lngTop;
            int lngRight;
            int lngBottom;
            //int lngPageCount=0;        //总页数

            FORMATRANGE fr;//格式化的文本范围
            RECT rcDrawTo;// As rect            '目标文字区域
            RECT rcPage;// As rect                  '目标页面区域
            int lngNextPos = 0;// As Long              '下一个字符位置
            int R;//As Long                       '返回值

            int lngPWidth;// As Long               '记录目标控件的原始尺寸
            int lngPHeight;// As Long

            lngPWidth = picBuff.Width;
            lngPHeight = picBuff.Height;
            //picBuff.Width = mvarPaperWidth
            //picBuff.Height = mvarPaperHeight

            //开始一个打印作业，用于获取有效的目标设备上下文句柄 hDC
            //picBuff.ScaleMode = vbTwips     '设置打印机单位为缇。
            int wtwips = SomeUtils.ConvertPixelsToTwips(picBuff.Width, MeasureDirection.Horizontal);
            int htwips = SomeUtils.ConvertPixelsToTwips(picBuff.Height, MeasureDirection.Horizontal);
            //'设置可打印页面区域
            rcPage.Left = 0;
            rcPage.Top = 0;
            rcPage.Right = wtwips;//todo use twips
            rcPage.Bottom = htwips;// picBuff.Height;//todo use twips
            int MarginLeft = 100;
            int MarginTop = 100;
            int MarginBottom = 100;
            int MarginRight = 100;//todo use twips
            //'设置可打印文字区域
            lngLeft = MarginLeft;
            lngTop = MarginTop;
            lngRight = wtwips - MarginRight;//todo use twips
            lngBottom = htwips - MarginBottom;//todo use twips

            rcDrawTo.Left = lngLeft;
            rcDrawTo.Top = lngTop;
            rcDrawTo.Right = lngRight;
            rcDrawTo.Bottom = lngBottom;

            //'设置打印指令（FormatRange消息需要的打印信息）
            IntPtr pichdc = picBuff.CreateGraphics().GetHdc();
            fr.hdc = pichdc;                // 渲染设备
            fr.hdcTarget = fr.hdc;          // 目标设备
            fr.rc = rcDrawTo;                // 文字矩形区域 IN/OUT
            fr.rcPage = rcPage;                  // 整个页面矩形区域 IN
            fr.chrg.cpMin = 0;                   // 打印区域的文字开始位置
            fr.chrg.cpMax = -1;                  // 文字结束位置（-1表示直到末尾）

            //'获取整个RTF文本长度
            int lngTmp = 0;// As Long              '用于记录单页字符起始位置
            AllPages = null;
            //'循环分页打印
            while (true)
            {
                //    '发送 EM_FORMATRANGE 消息进行虚拟打印
                IntPtr p1 = Marshal.AllocHGlobal(Marshal.SizeOf(fr));
                Marshal.StructureToPtr(fr, p1, true);
                lngNextPos = SendMessage(rtf.Handle, EM_FORMATRANGE, (uint)0, (uint)p1);//   '只分页，不打印
                if (lngNextPos <= lngTmp) { break; }// Then Exit Do    ' 完成所有页面的分页

                lngPageCount = lngPageCount + 1;//     ' 页数＋1
                //    '记录分页信息
                if (null == AllPages)
                {
                    AllPages = new PageInfo[lngPageCount];
                }
                else
                {
                    Array.Resize<PageInfo>(ref AllPages, lngPageCount);
                }
                //AllPages(1 To lngPageCount) As PageInfo
                AllPages[lngPageCount - 1].PageNumber = lngPageCount;
                AllPages[lngPageCount - 1].ActualHeight = fr.rc.Bottom - fr.rc.Top;//  '实际打印高度
                AllPages[lngPageCount - 1].Start = lngTmp;//
                AllPages[lngPageCount - 1].End = lngNextPos;//

                lngTmp = lngNextPos;

                fr.chrg.cpMin = lngNextPos;              // 下一页起始字符位置
                fr.hdc = pichdc;
                fr.hdcTarget = pichdc;
                fr.rc = rcDrawTo;                        // 必须重新设置文字区域，否则有误！
            }
            //PageCount = lngPageCount;
            //AllPages(lngPageCount).End = -1;//             ' 最后一页结束位置为最末尾
            //Label2.Caption = PageCount
            this.label1.Text = lngPageCount.ToString();
            this.numericUpDown1.Minimum = 1;
            this.numericUpDown1.Maximum = lngPageCount;
            //Call Me.MSpinEdit1.setRange(1, CInt(PageCount))
            //Call Me.MSpinEdit1.setPos(1)

            //'允许RTF释放内存
            //Object a = null;
            R = SendMessage(rtf.Handle, EM_FORMATRANGE, 0, 0);//
            this.PrintPage(ref rtf, 1, ref this.picBuff);
        }

        private void numericUpDown1_ValueChanged(object sender, EventArgs e)
        {
            this.PrintPage(ref this.richTextBox1, (int)numericUpDown1.Value, ref this.picBuff);
        }

    }
    [StructLayout(LayoutKind.Sequential)]
    internal struct RECT
    {
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;
    }
    [StructLayout(LayoutKind.Sequential)]
    internal struct CHARRANGE
    {
        public int cpMin;
        public int cpMax;
    }
    [StructLayout(LayoutKind.Sequential)]
    internal struct FORMATRANGE
    {
        public IntPtr hdc;             //渲染设备
        public IntPtr hdcTarget;       //目标设备
        public RECT rc;           //渲染区域，单位：缇。
        public RECT rcPage;          //渲染设备的整体区域，单位：缇。
        public CHARRANGE chrg;      //用于格式化的文本范围。
    }
    struct PageInfo
    {
        public int PageNumber;// As Long          '页码
        public int Start;// As Long                   '字符起始位置
        public int End;//As Long                     '字符终止位置
        public int ActualHeight;// As Long            '本页实际打印高度
    }

}